package studia.figlewicz.math.library;

import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class PrzeplywOpcyjnyAmerykanski extends PrzeplywPieniezny {
	
	public final static String[] instrumentyPodstawowe = {
		PrzeplywOpcyjnyEuropejski.CENA_INSTRUMENTU_PODSTAWOWEGO
	};
	public final static String CENA_INSTRUMENTU_PODSTAWOWEGO = Stale.PRZEPLYW_OPCYJNY_AMERYKANSKI_CENA_INSTRUMENTU_PODSTAWOWEGO;
	
	
	private Double strike;
	private TypOpcji typ = TypOpcji.CALL;
	private Set<Date> datyWykonania = new HashSet<Date>();


	// konstruktory
	public PrzeplywOpcyjnyAmerykanski(Date dataPrzeplywu, Double strike, TypOpcji typ, Double nominal) {
		super(dataPrzeplywu, nominal);
		this.strike = strike;
		this.typ = typ;
	}
	public PrzeplywOpcyjnyAmerykanski(Date dataPrzeplywu, Double strike, TypOpcji typ, Double nominal, double krokCzasowy, Date dataPoczatkowa) {
		super(dataPrzeplywu, nominal);
		this.strike = strike;
		this.typ = typ;
		generujDatyWykonania(krokCzasowy,dataPoczatkowa);
	}
	public PrzeplywOpcyjnyAmerykanski(Date dataPrzeplywu, Double strike, TypOpcji typ, Double nominal, Set<Date> datyWykonania) {
		super(dataPrzeplywu, nominal);
		this.strike = strike;
		this.typ = typ;
		this.datyWykonania = datyWykonania;
	}
	

	// gettery i settery
	@Override
	public String[] getInstrumentyPodstawowe() {
		return PrzeplywOpcyjnyAmerykanski.instrumentyPodstawowe;
	}
	public Double getStrike() {
		return strike;
	}
	public void setStrike(Double strike) {
		this.strike = strike;
	}
	public TypOpcji getTyp() {
		return typ;
	}
	public void setTyp(TypOpcji typ) {
		this.typ = typ;
	}
	public Set<Date> getDatyWykonania() {
		return datyWykonania;
	}
	public void setDatyWykonania(Set<Date> datyWykonania) {
		this.datyWykonania = datyWykonania;
	}
	
	
	// metody
	@Override
	public StatystykaWyceny obliczWyplate(Map<String, TrajektoriaProcesu> projekcje) {
		StatystykaWyceny resoult = null;
		
		TrajektoriaProcesu wynikProjekcji = projekcje.get(CENA_INSTRUMENTU_PODSTAWOWEGO);
		
		if (wynikProjekcji != null && wynikProjekcji != null)
			resoult = wyplataZTrajektorii(wynikProjekcji);

		return resoult;
	}
	
	
	// motody prywatne
	private StatystykaWyceny wyplataZTrajektorii(TrajektoriaProcesu trajektoriaCeny) {
		StatystykaWyceny resoult = new StatystykaWyceny();

		if (trajektoriaCeny != null) {
			
			// obliczanie funkcji wyplaty
			double maxNominalna = 0;
			double maxRealna = 0;
			for (Date data : datyWykonania) {
				double cena = trajektoriaCeny.znajdzWartosc(data).doubleValue();
				double wyplataNominalna = 0;
				double wyplataRealna = 0;
				
				double r = integral(stopaDyskonta, dataWyceny, data,1);
				double DF = 1 / (1 + r);
				
				if (typ == TypOpcji.CALL)
					wyplataNominalna = Math.max(0, cena - strike);
				else
					wyplataNominalna = Math.max(0, strike - cena);
				wyplataRealna = wyplataNominalna * DF;
				
				if (wyplataRealna * DF > maxRealna) {
					maxNominalna = wyplataNominalna;
					maxRealna = wyplataRealna;
				}
			}
			resoult.wartoscNominalna = new Double(maxNominalna);
			resoult.wartoscRealna = new Double(maxRealna);

			resoult.wartoscRealna = resoult.wartoscRealna.doubleValue() * nominal.doubleValue();
			resoult.wartoscNominalna = resoult.wartoscNominalna.doubleValue() * nominal.doubleValue();
		}
		
		return resoult;
	}
	
	private void generujDatyWykonania(double krokCzasowy, Date dataPoczatkowa) {
		// krok czasowy w dniach
		long roznica = dataPrzeplywu.getTime() - dataPoczatkowa.getTime();
		if (roznica < 0)
			return;
		else if (roznica == 0) {
			datyWykonania.add(dataPrzeplywu);
			return;
		}
		
		Date temp = new Date(dataPoczatkowa.getTime());
		while ( temp.compareTo(dataPrzeplywu) <= 0 ) {
			datyWykonania.add(new Date(temp.getTime()));
			temp = Utils.getNextDateDayFraction(temp, krokCzasowy);
		}
		// dodajemy tez ostatnia
		if (!datyWykonania.contains(dataPrzeplywu))
			datyWykonania.add(new Date(dataPrzeplywu.getTime()));
	}
	
	
	
}
